//
//  KUIModule.m
//  MengLiao
//
//  Created by xiuxin on 2022/7/15.
//  Copyright © 2022 ZHBen. All rights reserved.
//

#import "KUIModule.h"
#import "KMContext.h"
#import "KDDModel.h"
#import "KMConfigStore.h"

@interface KMStorage (KCombinedStorage)

- (void)insertStorageList:(NSArray<KMStorage *> *)storageList atIndexes:(NSIndexSet *)indexSet;

- (void)deleteStorageListAtIndexes:(NSIndexSet *)indexSet;

- (void)modifyStorageList:(NSArray<KMStorage *> *)storageList atIndexes:(NSIndexSet *)indexSet;

- (void)reloadStorageList:(NSArray<KMStorage *> *)storageList;

@end

@interface KMContext (KUIModule)

- (void)module:(KUIModule *)module didAddConfig:(KDDConfig *)config;

- (NSArray *)visibleModelsOfModule:(KUIModule *)module visibleViews:(NSArray<__kindof UIView<KMView> *> **)visibleViews;

@end

@interface KUIModule()

@property (strong,nonatomic) NSMutableDictionary<NSString *,id> * delegateInfo;

@end

@implementation KUIModule
{
    KMStorage * _storage;
}
@synthesize storage = _storage;
@dynamic data;
@dynamic index;

- (instancetype)init
{
    return [self initWithStorage:[KMStorage new]];
}

- (instancetype)initWithStorage:(KMStorage *)storage
{
    if (self = [super init])
    {
        self.delegateInfo = [NSMutableDictionary dictionary];
        _storage = storage;
        _moduleList = [NSMutableArray array];
    }
    return self;
}

- (void)setContext:(KMContext *)context
{
    _context = context;
}

- (NSInteger)index
{
    return _storage.index;
}

- (NSArray<KDDSectionData *> *)data
{
    return self.storage.localData;
}

- (BOOL)configModel:(NSObject *)model
{
    return [KMConfigStore configModel:model module:self];
}

- (void)loadModelList:(NSArray *)modelList
{
    [self loadData:[self sectionDataListOfModelList:modelList]];
}

- (void)loadSectionList:(NSArray<KDDSectionData *> *)sectionDataList
{
    for (KDDSectionData * sectionData in sectionDataList)
    {
        [self configSection:sectionData];
    }
    [self loadData:sectionDataList];
}

- (void)configSection:(KDDSectionData *)sectionData
{
    NSArray * modelList = sectionData.modelList;
    [sectionData clear];
    for (NSObject * model in modelList)
    {
        if ([self configModel:model])
        {
            if (![sectionData addModel:model viewType:model.ddViewType])
            {
                break;
            }
        }
    }
}

- (void)loadData:(NSArray<KDDSectionData *> *)sectionDataList
{
    if (sectionDataList.count == 0)
    {
        sectionDataList = @[[KDDSectionData new]];
    }
    [self.storage modifyData:sectionDataList];
}

- (NSArray<KDDSectionData *> *)sectionDataListOfModelList:(NSArray *)modelList
{
    KDDSectionData * sectionData = [KDDSectionData new];
    NSMutableArray<KDDSectionData *> * sectionDataList = [NSMutableArray arrayWithObject:sectionData];
    for (NSObject * model in modelList)
    {
        if ([self configModel:model])
        {
            if (![sectionData addModel:model viewType:model.ddViewType])
            {
                sectionData = [[KDDSectionData alloc] initWithSectionIndex:sectionData.index + 1];
                [sectionDataList addObject:sectionData];
                [sectionData addModel:model viewType:model.ddViewType];
            }
        }
    }
    return sectionDataList;
}

- (void)appointDelegate:(id)delegate forViewIDList:(NSArray<NSString *> *)viewIDList
{
    for (NSString * viewID in viewIDList)
    {
        self.delegateInfo[viewID] = delegate;
    }
}

- (id)appointedDelegateForViewID:(NSString *)viewID
{
    return self.delegateInfo[viewID];
}

- (__kindof UIView<KMView> *)viewOfModel:(NSObject *)model
{
    KDDPosition * physicalPosition = [self.context.dataDriven.storage positionOfModel:model inSection:-1];
    if (physicalPosition != nil)
    {
        UIView<KMWrapperView> * wrapperView = [self.context.dataDriven wrapperViewAtPosition:physicalPosition];
        return wrapperView.kmView;
    }
    return nil;
}

- (NSArray *)visibleModels:(NSArray<__kindof UIView<KMView> *> **)visibleViews
{
    return [self.context visibleModelsOfModule:self visibleViews:visibleViews];
}

- (void)insertModuleList:(NSArray<KUIModule *> *)moduleList atIndexes:(NSIndexSet *)indexSet
{
    if (self.moduleList.count == 0)
    {
        [self reloadModuleList:moduleList];
    }
    else
    {
        [self.moduleList insertObjects:moduleList atIndexes:indexSet];
        NSArray<KMStorage *> * storageList = [moduleList valueForKeyPath:@"storage"];
        [self.storage insertStorageList:storageList atIndexes:indexSet];
        [moduleList makeObjectsPerformSelector:@selector(setContext:) withObject:self.context];
    }
}

- (void)deleteModuleListAtIndexes:(NSIndexSet *)indexSet
{
    [[self.moduleList objectsAtIndexes:indexSet] makeObjectsPerformSelector:@selector(setContext:) withObject:nil];
    [self.moduleList removeObjectsAtIndexes:indexSet];
    [(KMStorage *)self.storage deleteStorageListAtIndexes:indexSet];
}

- (void)modifyModuleList:(NSArray<KUIModule *> *)moduleList atIndexes:(NSIndexSet *)indexSet
{
    [[self.moduleList objectsAtIndexes:indexSet] makeObjectsPerformSelector:@selector(setContext:) withObject:nil];
    [self.moduleList replaceObjectsAtIndexes:indexSet withObjects:moduleList];
    NSArray<KMStorage *> * storageList = [moduleList valueForKeyPath:@"storage"];
    [self.storage modifyStorageList:storageList atIndexes:indexSet];
    [moduleList makeObjectsPerformSelector:@selector(setContext:) withObject:self.context];
}

- (void)reloadModuleList:(NSArray<KUIModule *> *)moduleList
{
    [self.moduleList makeObjectsPerformSelector:@selector(setContext:) withObject:nil];
    self.moduleList = [NSMutableArray arrayWithArray:moduleList];
    NSArray<KMStorage *> * storageList = [moduleList valueForKeyPath:@"storage"];
    [self.storage reloadStorageList:storageList];
    [moduleList makeObjectsPerformSelector:@selector(setContext:) withObject:self.context];
}

- (BOOL)hasModel
{
    for (KDDSectionData * sectionData in [NSArray arrayWithArray:self.data])
    {
        if (![sectionData isEmpty])
        {
            return YES;
        }
    }
    return NO;
}

@end
